using System;
using System.Web.Routing;
using System.Web;
using System.Net;
using System.Xml.Linq;
using System.Xml;
using System.Linq;

namespace Odp.DataServices 
{
    public class sqlMetaDataHttpHandler : sqlTableStorageHttpHandlerBase, IHttpHandler
    {
        public string OgdiAlias { get; set; }        

        private readonly string START_DATASERVICES_TEMPLATE =
@"<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<edmx:Edmx Version='1.0' xmlns:edmx='http://schemas.microsoft.com/ado/2007/06/edmx'>
  <edmx:DataServices>
    <Schema Namespace='OGDI.{0}' xmlns:d='http://schemas.microsoft.com/ado/2007/08/dataservices' xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' xmlns='http://schemas.microsoft.com/ado/2007/05/edm'>
      <EntityContainer Name='{0}DataService' m:IsDefaultEntityContainer='true'>
";

        private readonly string ENTITYSET_TEMPLATE =
@"        <EntitySet Name='{0}' EntityType='OGDI.{1}.{2}' />
";

//        private const string END_ENTITYCONTAINER_TEMPLATE =
//@"      </EntityContainer>
//    </Schema>
//";
        private const string END_ENTITYCONTAINER_TEMPLATE =
@"      </EntityContainer>
";

//        private readonly string START_ENTITYTYPESCHEMA_TEMPLATE =
//@"    <Schema Namespace='" + AppSettings.RootServiceNamespace + @".{0}' xmlns:d='http://schemas.microsoft.com/ado/2007/08/dataservices' xmlns:m='http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' xmlns='http://schemas.microsoft.com/ado/2006/04/edm'>
//";

        private const string START_ENTITYTYPE_TEMPLATE =
@"      <EntityType Name='{0}'>
        <Key>
          <PropertyRef Name='PartitionKey' />
          <PropertyRef Name='RowKey' />
        </Key>
        <Property Name='PartitionKey' Type='Edm.String' Nullable='false' />
        <Property Name='RowKey' Type='Edm.String' Nullable='false' />
";
//@"      <EntityType Name='{0}'>
//        <Key>
//          <PropertyRef Name='PartitionKey' />
//          <PropertyRef Name='RowKey' />
//        </Key>
//        <Property Name='PartitionKey' Type='Edm.String' Nullable='false' />
//        <Property Name='RowKey' Type='Edm.String' Nullable='false' />
//        <Property Name='Timestamp' Type='Edm.DateTime' Nullable='false' />
//        <Property Name='entityid' Type='Edm.Guid' Nullable='false' />
//";

        private const string START_PROPERTY_TEMPLATE =
@"        <Property Name='{0}' Type='{1}' Nullable='{2}' />
";

        private const string END_ENTITYTYPE_TEMPLATE =
@"      </EntityType>
";

        private const string END_ENTITYTYPESCHEMA_TEMPLATE =
@"    </Schema>
";

        private const string END_DATASERVICES_TEMPLATE =
@"  </edmx:DataServices>
</edmx:Edmx>";

        #region IHttpHandler Members

        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            if (!this.IsHttpGet(context))
            {
                this.RespondForbidden(context);
            }
            else
            {
                context.Response.AddHeader("DataServiceVersion", "1.0;");
                context.Response.CacheControl = "no-cache";
                context.Response.ContentType = "application/xml;charset=utf-8";

								if(OgdiAlias.ToLower() != "sql")
								{
									context.Response.Write("Endpoint '"+OgdiAlias+"' does not exist.");
									context.Response.StatusCode = 404;//internal server error (int)response.StatusCode;
									context.Response.End();
									return;
								}

								//var accountName = AppSettings.EnabledStorageAccounts[this.OgdiAlias].storageaccountname;
								//var accountKey = AppSettings.EnabledStorageAccounts[this.OgdiAlias].storageaccountkey;

								//var requestUrl = AppSettings.TableStorageBaseUrl + "EntityMetadata";
								//WebRequest request = this.CreateTableStorageSignedRequest(context, accountName, accountKey,
								//                                                          requestUrl, false);

                try
                {
									context.Response.Write(string.Format(START_DATASERVICES_TEMPLATE, this.OgdiAlias.ToLower()));

									var sql = sqlServerConnection.GetDataServiceInstance();

									//OData does not support filtering metadata
									//string filter = context.Request.QueryString["$filter"];
									//if(!string.IsNullOrEmpty(filter))
									//  filter = filter.Replace("entityset","name");//TODO configure the right way

									var metadata = sql.GetTablesMetadata(/*filter,*/"",true);
									sql.Close();

									//overview of all EntitySets
									foreach (var data in metadata)
										context.Response.Write(string.Format(ENTITYSET_TEMPLATE, data.name, this.OgdiAlias, data.name+"Item"));
									context.Response.Write(END_ENTITYCONTAINER_TEMPLATE);

									//these are properties from the template which we'll ignore if found
									string[] fields = new string[] {"PartitionKey", "RowKey"};//, "Timestamp", "entityid"};
									
									//a detailed data for each EntitySet
									foreach (var data in metadata)
									{
										context.Response.Write(string.Format(START_ENTITYTYPE_TEMPLATE, data.name+"Item"));
										foreach(var pdata in data.properties)
										{
											//to be able to work with prepared templates
											//we have to get rid of entityid, which doesn't exist
											if (fields.Any(s => s.Equals(pdata.name)))
												continue;
												
											context.Response.Write(string.Format(START_PROPERTY_TEMPLATE, pdata.name, pdata.dataType, pdata.nullable));
										}
										context.Response.Write(END_ENTITYTYPE_TEMPLATE);
									}

									context.Response.Write(END_ENTITYTYPESCHEMA_TEMPLATE);
									context.Response.Write(END_DATASERVICES_TEMPLATE);

									//var response = request.GetResponse();
										//var responseStream = response.GetResponseStream();

										//var feed = XElement.Load(XmlReader.Create(responseStream));

										//context.Response.Write(string.Format(START_DATASERVICES_TEMPLATE, this.OgdiAlias.ToLower()));

										//var propertiesElements =  feed.Elements(_nsAtom + "entry").Elements(_nsAtom + "content").Elements(_nsm + "properties");
                    
									//foreach (var e in propertiesElements)
									//  {
									//      // Changed to use the simple approach of representing "entitykind" as
									//      // "entityset" value plus the text "Item."  A decision was made to do
									//      // this at the service level for now so that we wouldn't have to deal 
									//      // with changing the data import code and the existing values in the 
									//      // EntityMetadata table.
									//      // New notice: Import code was changed, so entityKind = entitySet + "Item" in storage for all new data
									//      // So return the code back:

									//      var entitySet = e.Element(_nsd + "entityset").Value;
									//      //var entityKind = entitySet + "Item";
									//      var entityKind = e.Element(_nsd + "entitykind").Value;
                        

									//      context.Response.Write(string.Format(ENTITYSET_TEMPLATE,
									//                                           entitySet,
									//                                           this.OgdiAlias,
									//                                           entityKind));	
									//}

										//context.Response.Write(END_ENTITYCONTAINER_TEMPLATE);
										////context.Response.Write(string.Format(START_ENTITYTYPESCHEMA_TEMPLATE, this.OgdiAlias));

									//  foreach (var e in propertiesElements)
									//  {
									//      //var entityKind = e.Element(_nsd + "entityset").Value + "Item";
									//      var entityKind = e.Element(_nsd + "entitykind").Value;

									//      context.Response.Write(string.Format(START_ENTITYTYPE_TEMPLATE, entityKind));

									//      e.Elements(_nsd + "PartitionKey").Remove();
									//      e.Elements(_nsd + "RowKey").Remove();
									//      e.Elements(_nsd + "Timestamp").Remove();
									//      e.Elements(_nsd + "entityset").Remove();
									//      e.Elements(_nsd + "entitykind").Remove();
									//      e.Elements(_nsd + "entityid").Remove();

									//      foreach (XElement prop in e.Elements())
									//      {	
									//          context.Response.Write(string.Format(START_PROPERTY_TEMPLATE, 
									//                                 prop.Name.LocalName, 
									//                                 prop.Value.Replace("System","Edm")));
									//      }

									//      context.Response.Write(END_ENTITYTYPE_TEMPLATE);
									//}

									//  context.Response.Write(END_ENTITYTYPESCHEMA_TEMPLATE);
									//  context.Response.Write(END_DATASERVICES_TEMPLATE);	
                }
                catch (Exception ex)
                {
									context.Response.Write(ex.Message);
									context.Response.StatusCode = 500;//internal server error (int)response.StatusCode;
									context.Response.End();
								}
            }
        }

        #endregion
    }
}
